#include "header.h"


LogFile *logFile;
LogFile *mainLogFile;
extern pthread_mutex_t LogFileLock;
extern std::map<uint16_t, int> statusNeighborNodes;

bool StatusFileOpen = false;
//bool statusTimeout = false;


void *dispatcher(void *ptr)
{
	//printf("DISPATCHER THREAD CREATED\n");
	
	while(1)
	{
		if(shutdownFlag == true || joinToTheNetworkFlag == true)
		{
			//printf("Dispatcher Thread EXIT due to Shutdown\n");
			pthread_exit(NULL);
		}
		
		pthread_mutex_lock(&ReadQueue);													//APPLY LOCK

		while (readQueue.size() == 0  && shutdownFlag == false)														//check if queue is empty
		{	
			pthread_cond_wait(&condition_var_Read, &ReadQueue);									// WAIT CONDITION
		}
		

		if(shutdownFlag == true || joinToTheNetworkFlag == true)
		{
			pthread_mutex_unlock(&ReadQueue);
			//printf("Dispatcher Thread EXIT due to Shutdown\n");
			pthread_exit(NULL);
		}
	
		Messages msg  = readQueue.front();											//get struct of msg from front of queue
		readQueue.pop_front();														// remove the msg from the front of queue 
		//printf("Msg Popped from Read Queue by Dispatcher\n");

		pthread_mutex_unlock(&ReadQueue);													//RELEASE LOCK

		
		//printf("msg header = %x-%x-%x-%x\n",msg.Header[0],msg.Header[1],msg.Header[2],msg.Header[3]);


		Header getHeader;
			
		getHeader.uoid = (unsigned char *)malloc(20* sizeof(char));
		memcpy(&getHeader.messageType,&msg.Header[0],1);
		memcpy(getHeader.uoid,&msg.Header[1],20);
		memcpy(&getHeader.ttl,&msg.Header[21],1);
		memcpy(&getHeader.reserved,&msg.Header[22],1);
		memcpy(&getHeader.dataLength,&msg.Header[23],4);
		
		
		//printf("Type = 0x%02x\n",getHeader.messageType);
		//printUOID(getHeader.uoid);
		//printf("TTL = %hhu\n",getHeader.ttl);
		//printf("Reserved = %hhu\n",getHeader.reserved);
		//printf("Datalength = %u\n",getHeader.dataLength);

		pthread_mutex_lock(&UoidMap);												//APPLY LOCK

		
		map<string,int>tempUoidMessageLifeTimeMap = node.getUoidMessageLifeTime();
		map<string,int>tempUoidSocketDescripter = node.getUoidSocketDescripter();
		string uoidStr = (const char*)getHeader.uoid;

		if(tempUoidMessageLifeTimeMap.find(uoidStr) == tempUoidMessageLifeTimeMap.end())	//check if UOID is already present in the list		
		{
			tempUoidMessageLifeTimeMap.insert(pair<string,int>(uoidStr,node.getMsgLifetime()));			// ADD uoid as it is not present
			tempUoidSocketDescripter.insert(pair<string,int>(uoidStr,msg.socketDescripter));
			//printf("Msg is inserted in map\n");
		}
		else													// else UOID is present
		{
			//printf("UOID is already present in map. Msg has arrived again\n");
			pthread_mutex_unlock(&UoidMap);															//RELEASE LOCK
			continue;
		}

		node.setUoidMessageLifeTime(tempUoidMessageLifeTimeMap);
		node.setUoidSocketDescripter(tempUoidSocketDescripter);
		//printf("Size of UoidMessageLifeTime=%d\n",node.getUoidMessageLifeTime().size());
		//printf("Size of UoidSocketDescripter=%d\n",node.getUoidSocketDescripter().size());
		
		

		pthread_mutex_unlock(&UoidMap);															//RELEASE LOCK




		//************************************************  JOIN REQUEST MESSAGE  ************************************************
		if(getHeader.messageType == joinRequestMessageType)													
		{
			//printf("Join Request Message Popped from Read Queue\n");
			if(getHeader.ttl > 1)									// if ttl is more than 1 
			{																							// FLOODING to each NEIGHBOR
				if((getHeader.ttl - 1) < node.getTTL())
				{
					getHeader.ttl = getHeader.ttl - 1;	//decrease ttl by 1
				}
				else
				{
					getHeader.ttl = node.getTTL();
				}

				//char *temp = (char *)malloc(sizeof(char));
				//memset(temp,'\0',28);
				memset(msg.Header,'\0',28);
				memcpy(&msg.Header[0],&getHeader.messageType,1);
				memcpy(&msg.Header[1],getHeader.uoid,20);
				memcpy(&msg.Header[21],&getHeader.ttl,1);
				memcpy(&msg.Header[22],&getHeader.reserved,1);
				memcpy(&msg.Header[23],&getHeader.dataLength,4);
								
					
				pthread_mutex_lock(&NeighborList);																//Apply LOCK
				multimap<string,int> tempMap = node.getNeighborList();
				pthread_mutex_unlock(&NeighborList);																//RELEASE LOCK

				multimap<string,int>::iterator it;

				int tempSock;
				for( it=tempMap.begin(); it!=tempMap.end(); it++)
				{
					tempSock = (*it).second;
					//printf("Neighbor socketdesc = %d\n",tempSock);
					if(tempSock != msg.socketDescripter)					// send to nodes other than the sender node 
					{
						//printf("Neighbor socketdesc = %d\n",tempSock);
						//printf("Msg sent to neighbor Type = 0x%02x\n",getHeader.messageType);
						//printUOID(getHeader.uoid);
						//printf("Msg sent to neighbor TTL = %hhu\n",getHeader.ttl);
						//printf("Msg sent to neighbor Reserved = %hhu\n",getHeader.reserved);
						//printf("Msg sent to neighbor Datalength = %u\n",getHeader.dataLength);
						pthread_mutex_lock(&WriteQueue[tempSock]);
						writeQueue[tempSock].push_back(msg);			//push to all neighbor the write queue
						//printf("Size of queue = %d\n",writeQueue[tempSock].size());
						pthread_cond_signal(&condition_var_Write[tempSock]);	
						pthread_mutex_unlock(&WriteQueue[tempSock]);
					}	
				}
			}			
			
																													// ADD JOIN RESPONSE
			unsigned int dataLength = (uint32_t)(20 + 4 + 2 + strlen(node.getHostName())); // UOID(20) + Distance(4) + Port(2) + Hostname
			Header putHeader = createHeader((uint8_t)joinResponseMessageType, dataLength);

			//printf("Join Response Type = 0x%02x\n",putHeader.messageType);
			//printUOID(putHeader.uoid);
			//printf("Join response TTL = %hhu\n",putHeader.ttl);
			//printf("Join response Reserved = %hhu\n",putHeader.reserved);
			//printf("Join response Datalength = %u\n",putHeader.dataLength);
			
																												
			uint32_t receivedLocation;
			memcpy(&receivedLocation,&msg.Data[0],4);
			//printf("Location = %u\n",receivedLocation);
			
			uint32_t distance = abs((int)(node.getLocation()- receivedLocation));			//abs of distance
			//printf("Distance = %u\n",distance);

			JoinResponseMessage joinRpseMsg = sendJoinReponse(getHeader.uoid,distance);

			Messages respMessage;
			respMessage.socketDescripter = msg.socketDescripter;
			
			respMessage.Header = (char*)malloc(28*sizeof(char));
			memset(respMessage.Header,'\0',28);
			memcpy(&respMessage.Header[0],&putHeader.messageType,1);
			memcpy(&respMessage.Header[1],putHeader.uoid,20);
			memcpy(&respMessage.Header[21],&putHeader.ttl,1);
			memcpy(&respMessage.Header[22],&putHeader.reserved,1);
			memcpy(&respMessage.Header[23],&putHeader.dataLength,4);
			

			respMessage.Data = (char*)malloc(dataLength*sizeof(char));
			memcpy(&respMessage.Data[0],joinRpseMsg.uoid,20);
			memcpy(&respMessage.Data[20],&joinRpseMsg.distance,4);
			memcpy(&respMessage.Data[24],&joinRpseMsg.port,2);
			memcpy(&respMessage.Data[26],joinRpseMsg.hostname,strlen(node.getHostName()));

			printUOID(joinRpseMsg.uoid);
			//printf("Distance = %u\n",joinRpseMsg.distance);
			//printf("port = %hu\n",joinRpseMsg.port);
			//printf("hostname = %s\n",joinRpseMsg.hostname);

			struct timeval t;
			gettimeofday(&t, NULL);
			enterLogMessage(msg,'r',t);
			
			pthread_mutex_lock(&WriteQueue[msg.socketDescripter]);
			writeQueue[msg.socketDescripter].push_back(respMessage);			//push to corresponding write queue
			pthread_cond_signal(&condition_var_Write[msg.socketDescripter]);	
			pthread_mutex_unlock(&WriteQueue[msg.socketDescripter]);
							
			
		}

		//************************************************  JOIN RESPONSE MESSAGE  ************************************************
		else if(getHeader.messageType == joinResponseMessageType)														
		{
			//printf("Join Response Received\n");
			JoinResponseMessage joinRpseMsg;
			joinRpseMsg.uoid = (unsigned char *)malloc(20* sizeof(char));
			joinRpseMsg.hostname = (char *)malloc((getHeader.dataLength-26)* sizeof(char));
			memcpy(joinRpseMsg.uoid,&msg.Data[0],20);
			memcpy(&joinRpseMsg.distance,&msg.Data[20],4);
			memcpy(&joinRpseMsg.port,&msg.Data[24],2);
			memcpy(joinRpseMsg.hostname,&msg.Data[26],getHeader.dataLength-26);
			
			//printUOID(joinRpseMsg.uoid);
			//printf("Join Response Received Distace = %u\n",joinRpseMsg.distance);
			//printf("Join Response Received Port = %hu\n",joinRpseMsg.port);
			//printf("Join Response Received Hostname = %s\n",joinRpseMsg.hostname);
			
			
			

			pthread_mutex_lock(&UoidMap);
			map<string,int> tempMap = node.getUoidSocketDescripter();
			pthread_mutex_unlock(&UoidMap);
			
			//printf("SIZE OF MAP = %d\n",tempMap.size());


			map<string,int>::iterator it;
			string str = (const char*)joinRpseMsg.uoid;
			it=tempMap.find(str);
			
			if(it == tempMap.end())			// FIND WHERE TO SEND THIS RESPONSE
			{
				//true if entry NOT FOUND. This should always go in else part
				//printf("THIS SHOULD NOT PRINT\n");
			}
			else
			{
				//printf("####Sending JOIN Response#### on sock desc =%d\n",it->second);
				//it->second;   this is the socketdescriptor where you need to send data

				struct timeval t;
				gettimeofday(&t, NULL);
				enterLogMessage(msg,'s',t);
	
				pthread_mutex_lock(&WriteQueue[it->second]);
				writeQueue[it->second].push_back(msg);			//push to corresponding write queue
				pthread_cond_signal(&condition_var_Write[it->second]);	
				pthread_mutex_unlock(&WriteQueue[it->second]);
			}
		}

		//************************************************  STATUS REQUEST MESSAGE  ************************************************
		
		else if(getHeader.messageType == statusRequestMessageType)
		{
			struct timeval t1;
			gettimeofday(&t1, NULL);
			enterLogMessage(msg,'r',t1);

			//printf("Status Request Message Popped from Read Queue\n");
			if(getHeader.ttl > 1)									// if ttl is more than 1 
			{																							// FLOODING to each NEIGHBOR
				if((getHeader.ttl - 1) < node.getTTL())
				{
					getHeader.ttl = getHeader.ttl - 1;	//decrease ttl by 1
					//printf("-1\n");
				}
				else
				{
					getHeader.ttl = node.getTTL();
				}
					
				//printf("After ttl\n");

				//char *temp = (char *)malloc(sizeof(char));
				//memset(temp,'\0',28);
				memset(msg.Header,'\0',28);
				memcpy(&msg.Header[0],&getHeader.messageType,1);
				memcpy(&msg.Header[1],getHeader.uoid,20);
				memcpy(&msg.Header[21],&getHeader.ttl,1);
				memcpy(&msg.Header[22],&getHeader.reserved,1);
				memcpy(&msg.Header[23],&getHeader.dataLength,4);
				//printf("After \n");
								
					
				pthread_mutex_lock(&NeighborList);																//Apply LOCK
				multimap<string,int> tempMap = node.getNeighborList();
				pthread_mutex_unlock(&NeighborList);																//RELEASE LOCK

				multimap<string,int>::iterator it;


				//printf("Neighbors size = %d\n",tempMap.size());
				int tempSock;
				for( it=tempMap.begin(); it!=tempMap.end(); it++)
				{
					tempSock = (*it).second;
					//printf("Neighbor socketdesc = %d\n",tempSock);
					if(tempSock != msg.socketDescripter)					// send to nodes other than the sender node 
					{
						//printf("Neighbor socketdesc = %d\n",tempSock);
						//printf("Msg Forwarded to neighbors Type = 0x%02x\n",getHeader.messageType);
						
						// forwarding it to other nodes
						struct timeval t4;
						gettimeofday(&t4, NULL);
						enterLogMessage(msg,'f',t4);

						//printUOID(getHeader.uoid);
						//printf("Msg sent to neighbor TTL = %hhu\n",getHeader.ttl);
						//printf("Msg sent to neighbor Reserved = %hhu\n",getHeader.reserved);
						//printf("Msg sent to neighbor Datalength = %u\n",getHeader.dataLength);
						pthread_mutex_lock(&WriteQueue[tempSock]);
						writeQueue[tempSock].push_back(msg);			//push to all neighbor the write queue
						//printf("Size of queue = %d\n",writeQueue[tempSock].size());
						pthread_cond_signal(&condition_var_Write[tempSock]);	
						pthread_mutex_unlock(&WriteQueue[tempSock]);
					}	
				}
			}
			
																				// SEND RESPONSE 
			//printf("After ttl\n");
			//uint16_t neighbourPort;
			 
			int recordLengthIndex=0;
			uint32_t recordLength=0;
			char* myData = (char*)malloc(512*sizeof(char));
			memset(myData,'\0',512*sizeof(char));
							

			char* neighbourHostName = (char*)malloc(50*sizeof(char));
			memset(neighbourHostName,'\0',50*sizeof(char));

			
			multimap<string,int> tempMap;
			pthread_mutex_lock(&NeighborList);																//Apply LOCK
			tempMap = node.getNeighborList();
			pthread_mutex_unlock(&NeighborList);																//RELEASE LOCK

			multimap<string,int>::iterator ii;
			multimap<string,int>::reverse_iterator rit;
			rit = tempMap.rbegin();
			// get the details of all my neighbours to create the status response	
			for( ii=tempMap.begin(); ii!=tempMap.end(); ii++)
			{ 	
				string hostnameport = (*ii).first;
				//printf("hostnameport = %s\n",hostnameport.c_str());
				int colon = hostnameport.find(":");
				string portstr = hostnameport.substr(colon+1);
				//printf("portstr = %s\n",portstr.c_str());

				istringstream finalport(portstr);
				uint16_t myport;
				finalport >> myport;
				//int port = atoi(portstr.c_str());
				string hostname = hostnameport.substr(0,colon);
				//printf("hostname = %s\n",hostname.c_str());


				//sscanf(((*ii).first).c_str(),"%s:%hu",neighbourHostName,&neighbourPort);
				//printf("port = %hu hostname = %s\n",myport,hostname.c_str() );
				recordLength = (uint32_t)sizeof(uint16_t)+ (uint32_t)(strlen(hostname.c_str()));//15
				//printf("DEBUG: LENGTH of hostname: %d, INSERTING DATA RECORDLEN: %hu \n",strlen(hostname.c_str()),recordLength);
				if((*ii).second == (*rit).second)
				{
					//printf("Last RECORD : at index: %d\n",recordLengthIndex);
					recordLength = 0;
					memcpy(&myData[recordLengthIndex], &recordLength,4);
				}
				else
				{
					//printf("RECORD : at index: %d\n",recordLengthIndex);
					//recordLength = 15;
					memcpy(&myData[recordLengthIndex], &recordLength,4);
				}
				
				//printf("HERE\n");	
				memcpy(&myData[recordLengthIndex+4],&myport,2);
				memcpy(&myData[recordLengthIndex+6],hostname.c_str(), 13);
				recordLengthIndex = recordLengthIndex + 19;
				//printf("!1111\n");
			}	
									
			//printf("rdlgth = %d\n",recordLengthIndex);
			//						printf("!2222\n");
			StatusResponseMessage statusRpseMsg = sendStatusResponse(getHeader.uoid,myData,recordLengthIndex);
			//printf("!333\n");
									
			// create the header
			int dataLength	= sizeof(uint16_t)+ strlen(node.getHostName()) + recordLengthIndex + 22; // 22 = uoid + host info length

			//printf("dataLength for 2 neighbors = %d\n",dataLength);
			//printf("SIZE OF NEIGHBOR LIST = %d\n",tempMap.size());
			Header putHeader = createHeader((uint8_t)statusResponseMessageType,dataLength);	
				
			Messages statusResponse;
			
			// 1. set socket descriptor
			statusResponse.socketDescripter=msg.socketDescripter;
			
			//2. set header
			statusResponse.Header = (char*)malloc(28*sizeof(char));
			memset(statusResponse.Header,'\0',28);
			memcpy(&statusResponse.Header[0],&putHeader.messageType,1);
			memcpy(&statusResponse.Header[1],putHeader.uoid,20);
			memcpy(&statusResponse.Header[21],&putHeader.ttl,1);
			memcpy(&statusResponse.Header[22],&putHeader.reserved,1);
			memcpy(&statusResponse.Header[23],&putHeader.dataLength,4);
			
			//3. set data
			statusResponse.Data = (char*)malloc(dataLength*sizeof(char));
			memcpy(&statusResponse.Data[0],statusRpseMsg.uoid,20);
			memcpy(&statusResponse.Data[20],&statusRpseMsg.hostInfoLength,2);
			memcpy(&statusResponse.Data[22],&statusRpseMsg.port,2);
			memcpy(&statusResponse.Data[24],statusRpseMsg.hostname,strlen(node.getHostName()));
			int hostnamesize = strlen(node.getHostName());
			memcpy(&statusResponse.Data[24 + hostnamesize],statusRpseMsg.data,recordLengthIndex);
			//printf("Response sent to node from where it came\n");
			//printf("statusResponse-----> %x-%x\n",statusResponse.Data[41],statusResponse.Data[42]);
							
			struct timeval t;
			gettimeofday(&t, NULL);
			enterLogMessage(statusResponse,'s',t);


			// add to the queue
			pthread_mutex_lock(&WriteQueue[msg.socketDescripter]);
			writeQueue[msg.socketDescripter].push_back(statusResponse);			//push to corresponding write queue
			pthread_cond_signal(&condition_var_Write[msg.socketDescripter]);	
			pthread_mutex_unlock(&WriteQueue[msg.socketDescripter]);
			
			free(myData);
		}


		//************************************************  STATUS RESPONSE MESSAGE  ************************************************
		else if(getHeader.messageType == statusResponseMessageType)
		{
			// status response received
			struct timeval t5;
			gettimeofday(&t5, NULL);
			enterLogMessage(msg,'r',t5);


			gettimeofday(&statusLast, NULL);

			if ((uint32_t)(statusLast.tv_sec - statusFirst.tv_sec) >= node.getMsgLifetime()) 
			{
				ctrlFlag = true;
			}
		
			//printf("STATUS RESPONSE RECEIVED\n");
									
			StatusResponseMessage statusRpseMsg; 
			statusRpseMsg.uoid = (unsigned char *)malloc(20*sizeof(char));
			statusRpseMsg.hostname = (char*)malloc(50*sizeof(char));
			statusRpseMsg.data = (char*)malloc(512*sizeof(char));
			char * tempdata= new char[512];
			memcpy(statusRpseMsg.uoid,&msg.Data[0],20);
			memcpy(&statusRpseMsg.hostInfoLength,&msg.Data[20],2);
			memcpy(&statusRpseMsg.port,&msg.Data[22],2);
			memcpy(statusRpseMsg.hostname,&msg.Data[24],13);							//13 bytes FIXED AS IT IS NUNKI.USC.EDU
			memcpy(statusRpseMsg.data,&msg.Data[37],getHeader.dataLength-37);
			//printf("DEBUG: The header data length: %d\n",getHeader.dataLength);
			memcpy(&tempdata[0],&msg.Data[37],getHeader.dataLength);

			//memcpy(&tempdata[0],"____",4);
			//memcpy(&tempdata[20],"__",2);

			//			printf("DEBUG: tmpdata length: %d \n",strlen(tempdata));
			// take the uoid and find in the map, if the socket is null , i am the receiver
			pthread_mutex_lock(&UoidMap);
			map<string,int> tempMap = node.getUoidSocketDescripter();
			pthread_mutex_unlock(&UoidMap);
			multimap<string,int>::iterator it;
						
			string uoid = (const char*)statusRpseMsg.uoid;
			it=tempMap.find(uoid);
			//printf("statusRpseMsg-------> %x-%x\n",statusRpseMsg.data[4],statusRpseMsg.data[5]);
			//printf("node.getUOIDStatus() %x-%x-%x-%x-%x-%x\n",abc[0],abc[1],abc[2],abc[3],abc[4],abc[5]);
			if(it == tempMap.end())									// FIND WHERE TO SEND THIS RESPONSE
			{
				//printf("NOT IN MAP\n");
				//if(strcmp((char*)statusRpseMsg.uoid,(char*)node.getUOIDStatus()) == 0)
				if(strcmp(uoid.c_str(),node.getUOIDStatus().c_str()) == 0)
				{
					//printf("I GENERATED THE REQUEST\n");
																				//I GENERATED STATUS RESQUEST
					// log the message and write it to a file
					//mainLogFile->WriteFilen("I am originator and final receiver of the message and commandtimeout is false\n");
					
					//extract hostname and port from the Status Response
					string sentFromHostname = statusRpseMsg.hostname;
					uint16_t sentFromPort = statusRpseMsg.port;
					//uint16_t hostinfolen = statusRpseMsg.hostInfoLength;
									
					// find out if the node has been written to a file
					
					map<uint16_t, int>::iterator iter;
					iter = statusNeighborNodes.find(sentFromPort); //find if the node has been entered
					
					if (iter == statusNeighborNodes.end()) 
					{
						//printf("Port Not present so INSERT\n");
						//Node not already written in the file
						if(ctrlFlag == false)
						{
							logFile->WriteFilen("n -t * -s ");
							logFile->WriteFile((int)sentFromPort);
							logFile->WriteFile(" -c red -i black");
							//printf("Log entered for port sentFromPort = %d\n",(int)sentFromPort);
							//Add the node and Port in map
							statusNeighborNodes.insert(pair<uint16_t, int>(sentFromPort, (int)sentFromPort));
						}
						
					}	
					// get the recordlength data
					uint32_t recordLen;						// each record length is 15 = nunki.usc.edu + port size
					memcpy(&recordLen, &(statusRpseMsg.data[0]),sizeof(uint32_t));
					//printf("recordLen = %hu\n",recordLen );
					//printf("Length of data = %s\n",statusRpseMsg.data);
					int recordIndex = 0;
					uint16_t NPort =(uint16_t)0;
					
					while (recordLen != 0)
					{
						//printf("If more than one record\n");
						//get the neighbor and port
						//memset(&NPort, 0, sizeof(uint16_t));
						NPort = 0;
						
						memcpy(	&NPort,	&statusRpseMsg.data[4+ recordIndex], sizeof(uint16_t)); //c is offset to get Port No each time
						//printf("DEBUG: statusRpseMsg.data[4+recordindex]= %s \n",statusRpseMsg.data[4+recordIndex]);
						//printf("NPORT = %hu\n",NPort);
						iter = statusNeighborNodes.find(NPort);
						
						if (iter == statusNeighborNodes.end())
						{ //write if not
							if( ctrlFlag == false)
							{
								logFile->WriteFilen("n -t * -s ");
								logFile->WriteFile((int)NPort);
								logFile->WriteFile(" -c red -i black");
								statusNeighborNodes.insert(pair<uint16_t, int>(NPort, NPort));
								//printf("Log entered for port neighbor = %d\n",(int)NPort);
							}							
						}

						if(ctrlFlag == false)
						{
							//add link for that neighbor
							logFile->WriteFilen("l -t * -s ");
							logFile->WriteFile((int)sentFromPort);
							logFile->WriteFile(" -d ");
							logFile->WriteFile((int)NPort);
							logFile->WriteFile(" -c blue");
						}
						
						
						recordIndex = recordIndex + recordLen + 4;
						//printf("Log entered for LINK sentFromPort n neighbor %d %d\n",(int)sentFromPort,NPort);
						//printf("Here printing the recordIndex after adding for last record= %d\n",recordIndex);
						recordLen=(uint32_t)0;
						//memset(&recordLen, 0, sizeof(uint32_t));
						memcpy(&recordLen,&(statusRpseMsg.data[recordIndex]),sizeof(uint32_t)); //c is modified , get new RLen
					}
				
					//fetch the final record
					if (recordLen == 0) 
					{
						//printf("LAST RECORD\n");
						//calculate the recordlength using Total Data Length
						//recordLen = getHeader.dataLength - 15; //get the last Recordlength
						recordLen = recordIndex;
						//printf("recordLen+4 = %d\n",(recordLen+4));
						uint16_t NPortL = 0;

						memcpy(&NPortL,&statusRpseMsg.data[recordLen+4], 2); //c is offset to get Port No each time
						//printf("NPortL = %u\n",NPortL);
						iter = statusNeighborNodes.find(NPortL);
						if (iter == statusNeighborNodes.end())
						{  
							//printf("Node\n");
							//printf("inside NPortL = %d\n",(int)NPortL);
							//write if not
							if(ctrlFlag == false)
							{
								logFile->WriteFilen("n -t * -s ");
								logFile->WriteFile((int)NPortL);
								logFile->WriteFile(" -c red -i black");
								statusNeighborNodes.insert(pair<uint16_t, int>(NPortL,(int) NPortL));
								//printf("Log entered for neighbor %d\n",NPortL);
							}							
						}
						if(ctrlFlag == false)
						{
							//add link for that neighbor
							//printf("link\n");
							logFile->WriteFilen("l -t * -s ");
							logFile->WriteFile((int)sentFromPort);
							logFile->WriteFile(" -d ");
							logFile->WriteFile((int)NPortL);
							logFile->WriteFile(" -c blue");
							//printf("Log entered for LINK sentFromPort n neighbor %d %d\n",(int)sentFromPort,NPortL);
						}
					}			
				}
			}
			else
			{
				// sending status response
				struct timeval t;
				gettimeofday(&t, NULL);
				enterLogMessage(msg,'s',t);


				//printf("####Sending STATUS Response#### on sock desc =%d\n",it->second);
				//it->second;   this is the socketdescriptor where you need to send data
				pthread_mutex_lock(&WriteQueue[it->second]);
				writeQueue[it->second].push_back(msg);			//push to corresponding write queue
				pthread_cond_signal(&condition_var_Write[it->second]);	
				pthread_mutex_unlock(&WriteQueue[it->second]);
				
			}
		}
		//************************************************  CHECK REQUEST MESSAGE  ************************************************
		else if(getHeader.messageType == checkRequestMessageType)													
		{		
		
			struct timeval t;
			gettimeofday(&t,NULL);
			enterLogMessage(msg,'r',t);
		
							
			// if it is a beacon node			
			if(IsBeaconNode)	
			{
				// respond to the message
				Header putHeader = createHeader((uint8_t)checkResponseMessageType,20);
				
				CheckResponseMessage checkRpseMsg = sendCheckResponse(getHeader.uoid);
				
				Messages checkResponse;
				checkResponse.socketDescripter=msg.socketDescripter;
				
				checkResponse.Header = (char*)malloc(28*sizeof(char));
				memset(checkResponse.Header,'\0',28);
				memcpy(&checkResponse.Header[0],&putHeader.messageType,1);
				memcpy(&checkResponse.Header[1],putHeader.uoid,20);
				memcpy(&checkResponse.Header[21],&putHeader.ttl,1);
				memcpy(&checkResponse.Header[22],&putHeader.reserved,1);
				memcpy(&checkResponse.Header[23],&putHeader.dataLength,4);
				
				checkResponse.Data = (char*)malloc(20*sizeof(char));
				memcpy(&checkResponse.Data[0],checkRpseMsg.uoid,20);
				
				//printUOID(checkRpseMsg.uoid);
												
				pthread_mutex_lock(&WriteQueue[msg.socketDescripter]);
				writeQueue[msg.socketDescripter].push_back(checkResponse);			//push to corresponding write queue
				pthread_cond_signal(&condition_var_Write[msg.socketDescripter]);	
				pthread_mutex_unlock(&WriteQueue[msg.socketDescripter]);
				
				free(checkResponse.Header);
				free(checkResponse.Data);
				
			}
			
			// else flood the message if I am not a beacon node
			else
			{		
				// decrement the ttl
				if(getHeader.ttl > 1)									// if ttl is more than 1 
				{																							// FLOODING to each NEIGHBOR
					if((getHeader.ttl - 1) < node.getTTL())
					{
						getHeader.ttl = getHeader.ttl - 1;	//decrease ttl by 1
					}
					else
					{
						getHeader.ttl = node.getTTL();
					}
					
					memset(msg.Header,'\0',28);
					memcpy(&msg.Header[0],&getHeader.messageType,1);
					memcpy(&msg.Header[1],getHeader.uoid,20);
					memcpy(&msg.Header[21],&getHeader.ttl,1);
					memcpy(&msg.Header[22],&getHeader.reserved,1);
					memcpy(&msg.Header[23],&getHeader.dataLength,4);
					
										
					checkUoidSockDesc.insert(pair<string,int>(uoidStr,msg.socketDescripter));
				


					// get the neighbour list
					pthread_mutex_lock(&NeighborList);																//Apply LOCK
					multimap<string,int> tempMap = node.getNeighborList();
					pthread_mutex_unlock(&NeighborList);																//RELEASE LOCK
					multimap<string,int>::iterator it;
								
					int tempSock =0;;
					for( it=tempMap.begin(); it!=tempMap.end(); it++)
					{
						tempSock = (*it).second;
						if(tempSock != msg.socketDescripter)					// send to nodes other than the sender node 
						{
							pthread_mutex_lock(&WriteQueue[tempSock]);
							writeQueue[tempSock].push_back(msg);			//push to all neighbor the write queue
							pthread_cond_signal(&condition_var_Write[tempSock]);	
							pthread_mutex_unlock(&WriteQueue[tempSock]);
						}	
					}
				}
			}
		}
		//************************************************  CHECK RESPONSE MESSAGE  ************************************************
		else if(getHeader.messageType == checkResponseMessageType)														
		{
		
			
			CheckResponseMessage checkRpseMsg;
			memcpy(&checkRpseMsg,msg.Data,getHeader.dataLength);

			string uoid1(msg.Data);
			int sockId;
			if(uoid1.compare(checkUOID) == 0 )
			{
				checkFlag = true;
			}
			else
			{
				if (checkUoidSockDesc.find(uoid1) == checkUoidSockDesc.end())
				{
					continue;
				}
				else
				{
					sockId = checkUoidSockDesc.find(uoid1)->second;
					
					pthread_mutex_lock(&WriteQueue[sockId]);
					writeQueue[sockId].push_back(msg);			//push to corresponding write queue
					pthread_cond_signal(&condition_var_Write[sockId]);	
					pthread_mutex_unlock(&WriteQueue[sockId]);
				}
			}
			

			/*
			map<string,int>::iterator it;

			pthread_mutex_lock(&UoidMap);
			map<string,int> tempMap = node.getUoidSocketDescripter();
			pthread_mutex_unlock(&UoidMap);
			
			string str = (const char*)checkRpseMsg.uoid;
			it=tempMap.find(str);
			
			if(it == tempMap.end())			// FIND WHERE TO SEND THIS RESPONSE
			{
				//true if entry NOT FOUND. This should always go in else part
				mainLogFile->WriteFile("Error : CHECK RESPONSE MESSAGE : No socket found to send the data in the map");
			}
			else
			{
				// if it->second is null, it means i am the originator of the message
				if(!it->second)
				{
				// log the message
				struct timeval t;
				gettimeofday(&t,NULL);
				enterLogMessage(msg,'r',t);
				}
				
				// if it->second is not null, send it to the one who sent it to me
				pthread_mutex_lock(&WriteQueue[it->second]);
				writeQueue[it->second].push_back(msg);			//push to corresponding write queue
				pthread_cond_signal(&condition_var_Write[it->second]);	
				pthread_mutex_unlock(&WriteQueue[it->second]);
			}
						*/
		}
		
	}
	return NULL;
}



